﻿using System.Xml.Linq;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Xom.Elements;
using Xom.UnitTests.Mocks;

namespace Xom.UnitTests
{
    /// <summary>
    /// Summary description for LinqToXmlEngineTests
    /// </summary>
    [TestClass]
    public class LinqToXmlEngineTests
    {
        public LinqToXmlEngineTests()
        {
        }

        /// <summary />
        [TestMethod]
        public void ReadEmptyStringXml()
        {
            //arrange
            StringTestObject test = XmlObjectMapper.Parse(GetEmptyStringTestXml(), typeof(StringTestObject)) as StringTestObject;
            //act
            //assert
            Assert.IsNotNull(test);
            Assert.IsNull(test.ReqElement);
            Assert.IsNull(test.ReqAttribute);
        }

        /// <summary />
        [TestMethod]
        public void AddMissingRequiredElement()
        {
            //arrange
            StringTestObject test = XmlObjectMapper.Parse(GetEmptyStringTestXml(), typeof(StringTestObject)) as StringTestObject;
            //act
            test.ReqElement = "XYZ";
            string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());

            //assert
            Assert.IsNotNull(test);
            Assert.IsTrue(xml.Contains("<string><reqElement>XYZ</reqElement>"));
        }

        /// <summary />
        [TestMethod]
        public void AddMissingOptionalElement()
        {
            //arrange
            StringTestObject test = XmlObjectMapper.Parse(GetEmptyStringTestXml(), typeof(StringTestObject)) as StringTestObject;
            //act
            test.OptElement2 = "XYZ";
            string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());

            //assert
            Assert.IsNotNull(test);
            Assert.IsTrue(xml.Contains("<string><optElement2>XYZ</optElement2>"));
        }

        /// <summary />
        [TestMethod]
        public void InsertMissingRequiredElement()
        {
            //arrange
            StringTestObject test = XmlObjectMapper.Parse(GetEmptyStringTestXml(), typeof(StringTestObject)) as StringTestObject;
            //act
            test.OptElement = "AAA";
            test.OptElement2 = "CCC";
            test.ReqElement = "BBB";
            string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());

            //assert
            Assert.IsNotNull(test);
            Assert.IsTrue(xml.Contains("<string><optElement>AAA</optElement><reqElement>BBB</reqElement><optElement2>CCC</optElement2>"));
        }

        /// <summary />
        [TestMethod]
        public void InsertMissingOptionalElement()
        {
            //arrange
            StringTestObject test = XmlObjectMapper.Parse(GetEmptyStringTestXml(), typeof(StringTestObject)) as StringTestObject;
            //act
            test.ReqElement = "BBB";
            test.OptElement2 = "CCC";
            test.OptElement = "AAA";
            string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());

            //assert
            Assert.IsNotNull(test);
            Assert.IsTrue(xml.Contains("<string><optElement>AAA</optElement><reqElement>BBB</reqElement><optElement2>CCC</optElement2>"));
        }

        /// <summary />
        [TestMethod]
        public void ReadComplexXmlProperties()
        {
            //arrange
            SimpleXmlTestObject test = XmlObjectMapper.Parse(GetComplexXml(), typeof(SimpleXmlTestObject)) as SimpleXmlTestObject;
            //act
            //assert
            Assert.IsNotNull(test);
            Assert.AreEqual((uint)100, test.Id);
            Assert.AreEqual((double)10.00, test.Value);
            Assert.IsNull(test.IsActive);
            Assert.IsNotNull(test.Control);
            Assert.AreEqual(0, test.Control.Index);
            Assert.AreEqual("abc", test.Control.Info);
            Assert.IsNull(test.Control.Note);
        }

        /// <summary />
        [TestMethod]
        public void UpdateComplexXmlProperty()
        {
            //arrange
            SimpleXmlTestObject test = XmlObjectMapper.Parse(GetComplexXml(), typeof (SimpleXmlTestObject)) as SimpleXmlTestObject;
            //act
            test.Control = new SimpleSubXmlTestObject{Index = 111};
            test.Control.Info = "New";
            string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());

            //assert
            Assert.IsTrue(xml.Contains("<sub index=\"111\">New</sub></simple>"));
        }

        /// <summary />
        [TestMethod]
        public void UpdateExistingXmlProperties()
        {
            //arrange
            SimpleXmlTestObject test = XmlObjectMapper.Parse(GetComplexXml(), typeof(SimpleXmlTestObject)) as SimpleXmlTestObject;
            //act
            test.Id = 999;
            test.Value = 9.0;
            test.IsActive = true;
            test.Control.Index = 1;
            test.Control.Info = "Test";

            string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());
            //assert
            Assert.IsTrue(xml.Contains("<simple Id=\"999\"><Value>9</Value><Active>true</Active><sub index=\"1\">Test</sub></simple>"));
        }

        /// <summary />
        [TestMethod]
        public void SetExistingShortOptionalElementToNull()
        {
            //arrange
            SimpleXmlTestObject test = XmlObjectMapper.Parse(GetComplexXml(), typeof(SimpleXmlTestObject)) as SimpleXmlTestObject;
            //act
            test.IsActive = null;
            string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());
            //assert
            Assert.IsTrue(xml.Contains("<simple Id=\"100\"><Value>10.00</Value><sub index=\"0\">"));
        }

        /// <summary />
        [TestMethod]
        public void SetExistingOptionalElementToNull()
        {
            //arrange
            SimpleXmlTestObject test = XmlObjectMapper.Parse(GetComplexXml(), typeof(SimpleXmlTestObject)) as SimpleXmlTestObject;
            //act
            test.Value = null;
            string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());
            //assert
            Assert.IsTrue(xml.Contains("<simple Id=\"100\"><Active /><sub index=\"0\">"));
        }

        /// <summary />
        [TestMethod]
        public void SetExistingOptionalElementToEmpty()
        {
            //todo write unit test
            //arrange
            //SimpleXmlTestObject test = XmlObjectMapper.Parse(GetComplexXml(), typeof(SimpleXmlTestObject)) as SimpleXmlTestObject;
            //act
            //test.Value = string.Empty;
            //string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());
            //assert
            //Assert.IsTrue(xml.Contains("<simple Id=\"100\"><Active /><sub index=\"0\">"));
        }

        /// <summary />
        [TestMethod]
        public void SetMissingOptionalAttributeToNull()
        {
            //arrange
            SimpleXmlTestObject test = XmlObjectMapper.Parse(GetComplexXml(), typeof(SimpleXmlTestObject)) as SimpleXmlTestObject;
            //act
            test.Name = null;
            string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());
            //assert
            Assert.IsTrue(xml.Contains("<simple Id=\"100\"><Value>10.00</Value>"));
        }

        /// <summary />
        [TestMethod]
        public void SetMissingOptionalAttributeToEmpty()
        {
            //arrange
            SimpleXmlTestObject test = XmlObjectMapper.Parse(GetComplexXml(), typeof(SimpleXmlTestObject)) as SimpleXmlTestObject;
            //act
            test.Name = string.Empty;
            string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());
            //assert
            Assert.IsTrue(xml.Contains("<simple name=\"\" Id=\"100\"><Value>10.00</Value>"));
        }

        /// <summary />
        [TestMethod]
        public void SetRequiredXmlAttributeToNull()
        {
            //todo write test
            //arrange
            SimpleXmlTestObject test = XmlObjectMapper.Parse(GetComplexXml(), typeof(SimpleXmlTestObject)) as SimpleXmlTestObject;
            //act
            //test.Id = null;
            string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());
            //assert
            //Assert.IsTrue(xml.Contains("<simple name=\"Test\" Id=\"999\"><Value>10.00</Value>"));
        }

        /// <summary />
        [TestMethod]
        public void WriteNewAttributeXmlProperties()
        {
            //arrange
            SimpleXmlTestObject test = XmlObjectMapper.Parse(GetComplexXml(), typeof(SimpleXmlTestObject)) as SimpleXmlTestObject;
            //act
            test.Name = "Test";
            string xml = XmlUnitTestHelper.GetXmlString(XmlObjectMapper.Save());
            //assert
            Assert.IsTrue(xml.Contains("<simple name=\"Test\" Id=\"100\"><Value>10.00</Value>"));
        }

        /// <summary />
        [TestMethod]
        public void InsertNewObjectAtListIndex0()
        {
            //arrange
            IXmlObjectMapper mapper = XmlObjectMapper.Create();
            SimpleXmlTestContainerObject testObject = mapper.Parse(GetListSimpleXml(), typeof(SimpleXmlTestContainerObject)) as SimpleXmlTestContainerObject;

            //act
            testObject.Items.Insert(0, new SimpleXmlTestObject { Name = "new simple", Control = new SimpleSubXmlTestObject() });
            string xml = mapper.Save();

            //assert
            Assert.AreEqual(true, xml.Contains("<container>\r\n  <simple name=\"new simple\" Id=\"0\">"));
        }

        /// <summary />
        [TestMethod]
        public void InsertNewObjectAtListIndex1()
        {
            //arrange
            IXmlObjectMapper mapper = XmlObjectMapper.Create();
            SimpleXmlTestContainerObject testObject = mapper.Parse(GetListSimpleXml(), typeof(SimpleXmlTestContainerObject)) as SimpleXmlTestContainerObject;

            //act
            testObject.Items.Insert(1, new SimpleXmlTestObject { Name = "new simple", Control = new SimpleSubXmlTestObject() });
            string xml = mapper.Save();

            //assert
            Assert.AreEqual(true, xml.Contains("abc</sub>\r\n  </simple>\r\n  <simple name=\"new simple\" Id=\"0\">"));
        }

        /// <summary />
        [TestMethod]
        public void InsertNewObjectAtListIndex2()
        {
            //arrange
            IXmlObjectMapper mapper = XmlObjectMapper.Create();
            SimpleXmlTestContainerObject testObject = mapper.Parse(GetListSimpleXml(), typeof(SimpleXmlTestContainerObject)) as SimpleXmlTestContainerObject;

            //act
            testObject.Items.Insert(2, new SimpleXmlTestObject { Name = "new simple", Control = new SimpleSubXmlTestObject() });
            string xml = mapper.Save();

            //assert
            Assert.AreEqual(true, xml.Contains("def</sub>\r\n  </simple>\r\n  <simple name=\"new simple\" Id=\"0\">"));
        }

        /// <summary />
        [TestMethod]
        public void InsertAndModifySubControls()
        {
            //arrange
            IXmlObjectMapper mapper = XmlObjectMapper.Create();
            SimpleXmlTestContainerObject testObject = mapper.Parse(GetListSimpleWithoutSubXml(), typeof(SimpleXmlTestContainerObject)) as SimpleXmlTestContainerObject;

            //act
            testObject.Items[0].Control = new SimpleSubXmlTestObject { Info = "Test" };

            testObject.Items.Insert(0, new SimpleXmlTestObject { Name = "new simple"});
            string xml = mapper.Save();

            //assert
            Assert.AreEqual(true, xml.Contains("<sub>Test</sub>"));
        }

        /// <summary />
        [TestMethod]
        public void ChangePropertiesWithLinq()
        {
            //arrange
            SimpleXmlTestObject test = XmlObjectMapper.Parse(GetComplexXml(), typeof(SimpleXmlTestObject)) as SimpleXmlTestObject;

            //act
            test.Id = 999;
            test.Name = "test";
            test.IsActive = null;
            test.Control.Info = "123";
            string xml = XmlObjectMapper.Save();

            //assert
            Assert.IsNotNull(test.RootNode);
            Assert.AreEqual("999", ((IXomNode<XElement>)test.RootNode).Value.Attribute("Id").Value);
            Assert.AreEqual(true, xml.Contains(@"Id=""999"""));
        }

        /// <summary />
        [TestMethod]
        public void ReadSimpleListObject()
        {
            //arrange
            //act
            SimpleListContainerObject test = XmlObjectMapper.Parse(GetSimpleListContainerXml(), typeof(SimpleListContainerObject)) as SimpleListContainerObject;

            test.ValueList[0] = "true1";
            test.ValueList.Add("New");
            test.ValueList.RemoveAt(1);

            //assert
            Assert.IsNotNull(test);
            Assert.AreEqual(4, test.ValueList.Count);
            Assert.AreEqual("true1", test.ValueList[0]);
        }

        private string GetSimpleXml()
        {
            return @"<?xml version=""1.0""?>   
                                <simple Id=""100""> 
                                    <Value>10.00</Value> 
                                </simple>";
        }

        private string GetComplexXml()
        {
            return @"<?xml version=""1.0""?>   
                                <simple Id=""100""> 
                                    <Value>10.00</Value>
                                    <Active/>
                                    <sub index=""0"">abc</sub>   
                                </simple>";
        }

        private string GetSimpleListContainerXml()
        {
            return @"<?xml version=""1.0""?>   
                                <Object> 
                                    <Value>true</Value>
                                    <Value>10.00</Value>
                                    <Value>Test</Value>
                                    <Value>123</Value>   
                                </Object>";
        }

        private string GetListSimpleXml()
        {
            return @"<?xml version=""1.0""?>
                            <container>   
                                <simple Id=""100""> 
                                    <Value>10.00</Value>
                                    <Active/>
                                    <sub index=""0"">abc</sub>   
                                </simple>
                                <simple Id=""200""> 
                                    <Value>9</Value>
                                    <Active/>
                                    <sub index=""0"">def</sub>   
                                </simple>
                            </container>";
        }

        private string GetListSimpleWithoutSubXml()
        {
            return @"<?xml version=""1.0""?>
                            <container>   
                                <simple Id=""100""> 
                                    <Value>10.00</Value>
                                    <Active/>
                                </simple>
                                <simple Id=""200""> 
                                    <Value>9</Value>
                                    <Active/> 
                                </simple>
                            </container>";
        }

        private string GetEmptyStringTestXml()
        {
            return @"<?xml version=""1.0""?>
                        <string />";
        }
    }
}
